//! \file NeuronLayer.h
//! \brief Defines the <code>fullsail_ai::NeuronLayer</code> class.
//! \author Cromwell D. Enage
#ifndef _FULLSAIL_AI_NEURON_LAYER_H_
#define _FULLSAIL_AI_NEURON_LAYER_H_

#include <vector>
#include "Neuron.h"

namespace fullsail_ai {

	//! \brief This interface provides convenience methods for accessing or modifying a layer of
	//! neurons at a time.
	//!
	//! <code>MlpNetwork</code> implementations of the feed-forward and backpropagation algorithms
	//! must work with this interface only in order to modify the underlying neuron data
	//!  as wellas to compute each neuron's activation values and certain error values.
	class NeuronLayer
	{
		std::vector<Neuron> neurons;

	public:
		//! \brief Returns an unmodifiable view of the neurons in this layer.
		//!
		//! \return  A <code>const</code> view of the neurons in this layer.
		inline std::vector<Neuron> const& getNeurons() const
		{
			return neurons;
		}

		//! \brief Initializes the neuron collection.
		//!
		//! If \a numberGenerator generates random numbers, then the neurons' weights and biases
		//! will also be random.
		//!
		//! \param   argumentCount         the number of elements in each \a arguments container
		//!                                that will be passed in as an argument to subsequent
		//!                                <code>feedForward()</code> calls.
		//! \param   activationValueCount  the number of elements in each \a activationValues
		//!                                container that will be passed in as an argument to
		//!                                subsequent <code>feedForward()</code> calls.
		//! \param   numberGenerator       a zero-argument function that returns a different
		//!                                integer each time it is invoked.
		//!
		//! \pre
		//!   - <code>0 \<</code> \a argumentCount
		//!   - <code>0 \<</code> \a activationValueCount
		//!   - The range of \a numberGenerator is <code>[0, RAND_MAX]</code>.
		//! \post
		//!   - Each neuron in this layer has as many weights as there will be elements in the
		//!     aforementioned \a arguments container.
		void initialize(std::size_t argumentCount, std::size_t activationValueCount,
		                int (*numberGenerator)());

		//! \brief Calculates the neuron layer's activation values.
		//!
		//! \param   arguments         the container of arguments that the neurons in this layer
		//!                            will evaluate.
		//! \param   activationValues  the container in which the activation values will be stored.
		//!
		//! \pre
		//!   - There are as many elements in the \a activationValues container as there are
		//!     neurons in this layer.
		void feedForward(std::vector<double> const& arguments,
		                 std::vector<double>& activationValues) const;

		//! \brief Helper method for computing the errors of the hidden layer.
		//!
		//! \note
		//!   - You should call the <code>MlpNetwork::computeHiddenErrors()</code> method instead
		//!     of this one unless you really want to figure out which layer to invoke this method
		//!     on and why.
		//!   - Do not call this method in order to compute the errors of the output layer.
		//!
		//! \param   arguments     the container of arguments that triggered the output errors of
		//!                        this neuron layer during feed-forward.
		//! \param   outputErrors  the container of errors in the neurons' outputs.
		//! \param   hiddenErrors  the container of error values to be computed for the layer
		//!                        whose activation values were fed forward to this layer.
		//!
		//! \pre
		//!   - There are as many elements in the \a hiddenErrors container as there are elements
		//!     in the \a arguments container.
		//!   - There are as many elements in the \a outputErrors container as there are neurons
		//!     in this layer.
		void computeHiddenErrors(std::vector<double> const& arguments,
		                         std::vector<double> const& outputErrors,
		                         std::vector<double>& hiddenErrors) const;

		//! \brief Updates the weights and biases of the neurons in this layer.
		//!
		//! \param   arguments       the container of arguments that triggered the outputs of this
		//!                          neuron layer during feed-forward.
		//! \param   valueErrors     the container of errors in the neurons' outputs.
		//! \param   learningFactor  the rate at which the overall network makes progress in
		//!                          learning.
		//!
		//! \pre
		//!   - There are as many elements in the \a valueErrors container as there are neurons in
		//!     this layer.
		//!   - <code>0 \<</code> \a learningFactor
		void backPropagate(std::vector<double> const& arguments,
		                   std::vector<double> const& valueErrors, double learningFactor);
	};
}  // namespace fullsail_ai

#endif  // _FULLSAIL_AI_NEURON_LAYER_H_

